﻿namespace ExcelToolTest{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Xml;
    public class Metalib {
        public bool common = false;
        public string lib_name { private set; get; }

        private Dictionary<string, int> m_const = new Dictionary<string, int>(); //常量
        private List<ClassSet> m_classSets = new List<ClassSet>();      //基础数据定义，包括最外层定义和数据源
        private Dictionary<string, BaseSetAny> m_referenceSets = new Dictionary<string, BaseSetAny>();   //所有引用的数据定义
        public List<ClassSet> ClassSets
        {
            get { return m_classSets; }
        }
        public Dictionary<string, int> Const 
        {
            get { return m_const; }
        }
        public Dictionary<string, BaseSetAny> ReferenceSets
        {
            get { return m_referenceSets; }
        }
        public bool ParseXmlInfo(XmlElement xmlMetaLib) {
            lib_name = xmlMetaLib.GetAttribute(XML_ATTR_NAME.NAME);
            Reporter.SetMetalibProgress(lib_name);

            //const
            XmlNodeList constList = xmlMetaLib.GetElementsByTagName(XML_ELEMENTS_NAME.CONST);
            foreach(XmlElement ele in constList) {
                try {
                    int value = Convert.ToInt32(ele.GetAttribute(XML_ATTR_NAME.VALUE));
                    m_const.Add(ele.GetAttribute(XML_ATTR_NAME.NAME), value);
                }
                catch(Exception) {
                    Reporter.PushError("转换Const失败");
                    return false;
                }
            }

            //class set 
            XmlNodeList classSetList = xmlMetaLib.GetElementsByTagName(XML_ELEMENTS_NAME.CLASS);
            if(!common) {
                foreach(XmlElement classSet in classSetList) {
                    Reporter.SetSetProgress(classSet.GetAttribute(XML_ATTR_NAME.NAME));

                    ClassSet c_set = new ClassSet(this);
                    if(!c_set.ParseXmlInfo(classSet)) return false;

                    m_classSets.Add(c_set);
                }
            }
            else if(classSetList.Count > 0){
                //共用定义了不允许定义class(有数据源的结构)
                StringBuilder error_sb = new StringBuilder();
                foreach(XmlElement classSet in classSetList) {
                    string name = classSet.GetAttribute(XML_ATTR_NAME.NAME);
                    error_sb.AppendFormat("{0} |", name);
                }
                Reporter.PushError("共用枚举中定义了class : {0}", error_sb.ToString());
                return false;
            }

            //subclass set
            XmlNodeList subClassSetList = xmlMetaLib.GetElementsByTagName(XML_ELEMENTS_NAME.SUBCLASS);
            foreach(XmlElement subClassSet in subClassSetList) {
                Reporter.SetSetProgress(subClassSet.GetAttribute(XML_ATTR_NAME.NAME));

                SubClassSet sc_set = new SubClassSet(this);
                if(!sc_set.ParseXmlInfo(subClassSet)) return false;

                m_referenceSets.Add(sc_set.name, sc_set);
            }

            //group set
            XmlNodeList groupSetList = xmlMetaLib.GetElementsByTagName(XML_ELEMENTS_NAME.GROUP);
            foreach(XmlElement groupSet in groupSetList) {
                Reporter.SetSetProgress(groupSet.GetAttribute(XML_ATTR_NAME.NAME));

                GroupSet gset = new GroupSet(this);
                if(!gset.ParseXmlInfo(groupSet)) return false;

                m_referenceSets.Add(gset.name, gset);
            }

            //enum set 
            XmlNodeList enumSetList = xmlMetaLib.GetElementsByTagName(XML_ELEMENTS_NAME.ENUM);
            foreach(XmlElement enumSet in enumSetList) {
                Reporter.SetSetProgress(enumSet.GetAttribute(XML_ATTR_NAME.NAME));

                EnumSet e_set = new EnumSet(this);
                if(!e_set.ParseXmlInfo(enumSet)) return false;

                m_referenceSets.Add(e_set.name, e_set);
            }


            //todo validate
            XmlNodeList validSetList = xmlMetaLib.GetElementsByTagName(XML_ELEMENTS_NAME.VALID);
            if (validSetList.Count > 1)
            {
                Reporter.PushError("检测到多组validation配置！请只保留一组");
                return false;
            }

            if (validSetList.Count == 1)
            {
                XmlElement validation = validSetList[0] as XmlElement;

                XmlNodeList ref_list = validation.GetElementsByTagName(XML_ELEMENTS_NAME.REF);
                foreach (XmlElement ref_it in ref_list)
                {
                
                }
            }



            Reporter.ParseFinish();

            return true;
        }

        public bool ConstReferencValid(string const_name) {
            if(m_const.ContainsKey(const_name)) {
                return true;
            }

            return false;
        }

        public Metalib(bool common_use) {
            this.common = common_use;
        }

    }

    #region Set结构, 多条field组成一组Set
    public abstract class BaseSetAny {
        public string name;
        public string type;
        public string desc;

        public Metalib ParentLib { get; }

        public virtual bool ParseXmlInfo(XmlElement xmlInfo) {
            name = xmlInfo.GetAttribute(XML_ATTR_NAME.NAME);
            desc = xmlInfo.GetAttribute(XML_ATTR_NAME.DESC);

            return true;
        }
        public BaseSetAny(Metalib _p) {
            ParentLib = _p; 
        }
    } 
    public class BaseSetElement : BaseSetAny{
        protected List<FieldEntry> m_fieldCfg = new List<FieldEntry>();
        public List<FieldEntry> FieldCfg
        {
            get { return m_fieldCfg; }
        }
        protected int primary_idx = -1;
        public override bool ParseXmlInfo(XmlElement xmlInfo) {
            base.ParseXmlInfo(xmlInfo);
            XmlNodeList children =  xmlInfo.GetElementsByTagName(XML_ELEMENTS_NAME.ENTRY);

            foreach(XmlElement child in children) {
                Reporter.SetEntryProgress(child.GetAttribute(XML_ATTR_NAME.NAME));

                FieldEntry field = new FieldEntry(this);
                if(!field.ParseXmlInfo(child)) return false;

                if(field.Primary) {
                    if(primary_idx >= 0) {
                        Reporter.PushError("同一个结构体中定义了多条Primary数据！");
                        return false;
                    }
                    if(!XML_DATA_TYPE_NAME.PrimaryKeyType(field.type)) {
                        Reporter.PushError("类型{0}不能作为主键, 请使用int、string或enum类型作为主键", field.type);
                        return false;
                    }
                    primary_idx = m_fieldCfg.Count; 
                }
                m_fieldCfg.Add(field);
            }

            if(primary_idx == -1 && type == XML_DATA_TYPE_NAME.CLASS) {
                Reporter.PushError("必须在Class元素中定义一条含有primary属性的Entry作为主键!");
                return false;
            }

            if(primary_idx >= 0 && type != XML_DATA_TYPE_NAME.CLASS) {
                Reporter.PushError("检测到在非Class元素中含有primary属性的Entry，该primary属性将不会生效，请去除！");
                return false;
            }

            return true;
        }
        public BaseSetElement(Metalib _p) : base(_p) { }
    }

    public class SubClassSet : BaseSetElement {

        public SubClassSet(Metalib _p) : base(_p){
            type = XML_DATA_TYPE_NAME.SUBCLASS;
        } 
    }

    public class ClassSet : SubClassSet {
        public int TotalDataCount;
        private List<string> m_dataSourceList = new List<string>();
        public List<string> DataSourceList
        {
            get { return m_dataSourceList; }
        }

        private Dictionary<string, string> m_primaryValCache;
        public ClassSet(Metalib _p) : base(_p){
            m_primaryValCache = new Dictionary<string, string>();
            type = XML_DATA_TYPE_NAME.CLASS;
        }
        public override bool ParseXmlInfo(XmlElement xmlInfo) {
            if(!base.ParseXmlInfo(xmlInfo)) return false;
            XmlNodeList sourceCfg = xmlInfo.GetElementsByTagName(XML_ELEMENTS_NAME.DATASOURCE);
            foreach(XmlElement item in sourceCfg) {
                string tbName = item.GetAttribute(XML_ATTR_NAME.TBNAME);
                m_dataSourceList.Add(tbName);
            }
            return true;
        }
        public bool CachePrimaryValue(string value, string debug_location_str) {
            m_primaryValCache.Add(value, debug_location_str);
            return true;
        }
        public bool CheckUniqueness(string value, out string debug_str) {
            m_primaryValCache.TryGetValue(value, out debug_str);
            return !m_primaryValCache.ContainsKey(value);
        }
    }


    public class GroupSet : BaseSetElement {

        public GroupSet(Metalib _p) : base(_p){
            type = XML_DATA_TYPE_NAME.GROUP;
        }
    }

    public class EnumSet : BaseSetAny {
        public static readonly int INVALID_VALUE = int.MinValue;
        protected List<EnumEntry> m_enumEntry = new List<EnumEntry>();
        public List<EnumEntry> EntryList 
        {
            get { return m_enumEntry; }
        }
        public EnumSet(Metalib _p) : base(_p){
            type = XML_DATA_TYPE_NAME.ENUM;
        }

        public override bool ParseXmlInfo(XmlElement xmlInfo) {
            base.ParseXmlInfo(xmlInfo);
            XmlNodeList enum_value_list = xmlInfo.GetElementsByTagName(XML_ELEMENTS_NAME.ENTRY);
            foreach(XmlElement ele in enum_value_list) {
                Reporter.SetEntryProgress(ele.GetAttribute(XML_ATTR_NAME.NAME));

                EnumEntry entry = new EnumEntry(this);
                if(!entry.ParseXmlInfo(ele)) return false;
                m_enumEntry.Add(entry);
            }

            return true;
        }

        public int GetEnumValue(string enum_entry_key) {
            foreach(EnumEntry entry in m_enumEntry) {
                if(entry.key == enum_entry_key) {
                    return entry.value;
                }
            }

            return INVALID_VALUE;
        }
    }
    #endregion

    #region entry结构, 描述了某一列或某一组数据的对应关系, 或是枚举Set中的一个枚举值
    public class FieldEntry : BaseEntryElement{
        public string type;
        public string type_param;
        public string desc;

        public bool Primary;
        public int count = 0;
        public string count_str;
        public int valid_rule; //todo

        private bool tryParseCountAttr(XmlElement entryXml) {
            if (!entryXml.HasAttribute(XML_ATTR_NAME.COUNT))
            {
                //没有Count属性字段，则默认count = 1
                count = 1;
                return true;
            }

            //填写了但是解析不出含义，则抛错
            count_str = entryXml.GetAttribute(XML_ATTR_NAME.COUNT);

            if(int.TryParse(count_str, out count)) {
                //先尝试转换为int
                count_str = "";
                return true; 
            }
            else if(ParentSet.ParentLib.Const.TryGetValue(count_str, out count)) {
                //再尝试查找全局
                return true;
            }
            Reporter.PushError("Count属性字段解析失败，请引用本Metalib中的const条目,或直接填写数字");
            return false;
        }
        public override bool ParseXmlInfo(XmlElement xmlInfo) {
            base.ParseXmlInfo(xmlInfo);

            type = xmlInfo.GetAttribute(XML_ATTR_NAME.TYPE);
            type_param = xmlInfo.GetAttribute(XML_ATTR_NAME.TYPE_PARAM);
            desc = xmlInfo.GetAttribute(XML_ATTR_NAME.DESC);

            if(!tryParseCountAttr(xmlInfo)) return false;
            

            if(xmlInfo.GetAttribute(XML_ATTR_NAME.PRIMARY) == "true") {
                if (xmlInfo.HasAttribute(XML_ATTR_NAME.COUNT))
                {
                    Reporter.PushError("主键entry不允许配置count字段");
                    return false;
                }
                Primary = true;
            }
            else {
                Primary = false;
            }

            return true;
        }
        public FieldEntry(BaseSetAny _p): base(_p){}
    }

    public class EnumEntry : BaseEntryElement{
        public int value;

        public override bool ParseXmlInfo(XmlElement xmlInfo) {
            base.ParseXmlInfo(xmlInfo);

            string value_str = xmlInfo.GetAttribute(XML_ATTR_NAME.VALUE);
            try {
                value = Convert.ToInt32(value_str);
            }
            catch(Exception e) {
                Reporter.PushError("解析枚举值失败 : {0}", e.ToString());
                return false;
            }

            return true;
        }

        public EnumEntry(BaseSetAny _p): base(_p){}
    }

    public class BaseEntryElement {
        public string name;
        public string key;

        public BaseSetAny ParentSet { get; }

        public virtual bool ParseXmlInfo(XmlElement xmlInfo) {
            name = xmlInfo.GetAttribute(XML_ATTR_NAME.NAME);
            key = xmlInfo.GetAttribute(XML_ATTR_NAME.KEY);

            return true;
        }

        public BaseEntryElement(BaseSetAny _p) {
            ParentSet = _p;
        }
    }
    #endregion

    #region Valid结构
    public class ValidConfig {
        public int id;


    } 
    #endregion
}
